#include "dvbinner.h"
#include "camusb.h"
#include "app_main.h"
#include "spts.h"
#include "httpd.h"

#define DVB_SCAN_OPERATOR_PROCESS 20

typedef enum
{
	DVB_SCAN_TYPE_MANUAL,
	DVB_SCAN_TYPE_AUTO,
	DVB_SCAN_TYPE_FULL,
	DVB_SCAN_TYPE_NIT,
	DVB_SCAN_TYPE_IDLE,
}DVB_SCAN_TYPE_T;

pfDVBCallback pfCallback = NULL;
static DVB_SCAN_TYPE_T eCurrentScan = DVB_SCAN_TYPE_IDLE;
static unsigned int u32StartFreq = 0;
static unsigned int u32EndFreq = 0;

static void DVBInitCallback(int status)
{
	unsigned int param;
	void* pParam;

	if(pfCallback)
	{
		if(status == 0 )
			param = MSG_SYSTEM_INIT_OK;
		else
			param = MSG_SYSTEM_ERROR;
		pParam = NULL;
		pfCallback(DVB_CB_TYPE_SYSTEM, param, pParam);
	}
	return;
}

static void DVBSearchCallback(builder_callback_param_t* pstParam)
{
	dvb_network_t stNetwork;
	dvb_process_t stProcess;
	builder_scan_services_t stSanServices;
	void* pParamServiceInfo = NULL;
	unsigned int param;
	void* pParam;

	if(pfCallback)
	{
		switch(pstParam->m_eStage)
		{
			case BUILDER_START:	
				param = MSG_SCAN_START;
				pParam = &pstParam->m_uParam.m_stTunerInfo;
				pfCallback(DVB_CB_TYPE_SCAN, param, pParam);
				break;
			case BUILDER_TUNER_LOCK:
				param = MSG_SCAN_TUNER_LOCKED;
				pParam = &pstParam->m_uParam.m_stLockStatus;
				pfCallback(DVB_CB_TYPE_SCAN, param, pParam);
				break;
			case BUILDER_IN_PROCESS:
				param = MSG_SCAN_PROGRESS_CHANGED;
				if(eCurrentScan == DVB_SCAN_TYPE_AUTO || eCurrentScan == DVB_SCAN_TYPE_FULL)
					stProcess.m_u32Process = DVB_SCAN_OPERATOR_PROCESS+(100 - DVB_SCAN_OPERATOR_PROCESS)*pstParam->m_uParam.m_u32Process/100;
				else
					stProcess.m_u32Process = pstParam->m_uParam.m_u32Process;
				pParam = &stProcess;
				pfCallback(DVB_CB_TYPE_SCAN, param, pParam);
				break;
			case BUILDER_STAGE_FINISH:
				param = MSG_SCAN_SERVICES_FOUND;
				stSanServices.m_u32Cnt = pstParam->m_uParam.m_stServiceInfo.m_u32Cnt;
				stSanServices.m_pstServices = (builder_scan_service_t*)mwOsAllocMemory(sizeof(builder_scan_service_t)*stSanServices.m_u32Cnt);
				if(stSanServices.m_pstServices)
				{
					unsigned int i;
					for(i=0; i<stSanServices.m_u32Cnt; i++)
					{
						memcpy(stSanServices.m_pstServices[i].m_s8Name, pstParam->m_uParam.m_stServiceInfo.m_pstServices[i].m_s8Name, sizeof(stSanServices.m_pstServices[i].m_s8Name));
						stSanServices.m_pstServices[i].m_u16ServiceId = pstParam->m_uParam.m_stServiceInfo.m_pstServices[i].m_u16ServiceId;
						stSanServices.m_pstServices[i].m_u8Encrypt = pstParam->m_uParam.m_stServiceInfo.m_pstServices[i].m_u8Encrypt;
						if(pstParam->m_uParam.m_stServiceInfo.m_pstServices[i].m_u8ServiceType == SERVICETYPE_VIDEO)
							stSanServices.m_pstServices[i].m_u8ServiceType = DVB_GROUP_TV;
						else if(pstParam->m_uParam.m_stServiceInfo.m_pstServices[i].m_u8ServiceType == SERVICETYPE_AUDIO)
							stSanServices.m_pstServices[i].m_u8ServiceType = DVB_GROUP_RADIO;
						else
							stSanServices.m_pstServices[i].m_u8ServiceType = DVB_GROUP_USER_DEFINE;
							
					}
					pParam = &stSanServices;
					pfCallback(DVB_CB_TYPE_SCAN, param, pParam);
					mwOsFreeMemory(stSanServices.m_pstServices);
				}
				break;
			case BUILDER_SCAN_IN_PROCESS:
				param = MSG_SCAN_PROGRESS_CHANGED;
				stProcess.m_u32Process = DVB_SCAN_OPERATOR_PROCESS*pstParam->m_uParam.m_u32Process/100;
				pParam = &stProcess;
				pfCallback(DVB_CB_TYPE_SCAN, param, pParam);
				break;
			case BUILDER_SCAN_FINISH:
				//if(pstParam->m_eErrorCode == BUILDER_ECODE_SUCCESS)
				{
					param = MSG_SCAN_DVB_NETWORK;
					pParam = &pstParam->m_uParam.m_stNetworkInfo;
					pfCallback(DVB_CB_TYPE_SCAN, param, pParam);
				}
				break;
			case BUILDER_END:
				param = MSG_SCAN_FINISH;
				pParam = NULL;
				pfCallback(DVB_CB_TYPE_SCAN, param, pParam);
				eCurrentScan = DVB_SCAN_TYPE_IDLE;
				break;	
		}
	}
	return;	
}

int DVBSetServiceGroupId(unsigned int u32GroupId)
{
	int ret = 0;
	
	mwDebug("DVBSetServiceGroupId() - entry, u32GroupId = %d\r\n", u32GroupId);
	if(u32GroupId == DVB_GROUP_TV)
	{
		DVBGroupSetCurGroupByID(GROUP_VIDEO);
	}
	else if(u32GroupId == DVB_GROUP_RADIO)
	{
		DVBGroupSetCurGroupByID(GROUP_AUDIO);
	}
	else
	{
		mwError("DVBSetServiceGroupId() - receive error group type, u32GroupId = %d\r\n", u32GroupId);
		ret = -1;
	}
	mwDebug("DVBSetServiceGroupId() - return\r\n");
	
	return ret;
}

int DVBGetServiceGroupId(unsigned int* pu32GroupId)
{
	int ret = 0;
	
	mwDebug( "DVBGetServiceGroupId() - entry\r\n");
	if(pu32GroupId)
	{
		ret = DVBGroupGetCurGroupID(pu32GroupId);
	}
	else
	{
		mwError("DVBGetServiceGroupId() - receive NULL pu32GroupId\r\n");
		ret = -1;
	}
	mwDebug( "DVBGetServiceGroupId() - return\r\n");
	
	return ret;
}

int DVBRestoreSettings()
{
	int ret = 0;
	
	mwDebug( "DVBRestoreSettings() - entry\r\n");
	ret = DVBRestoreFactorySetting();
	mwDebug( "DVBRestoreSettings() - return\r\n");
	
	return ret;
}

dvb_time_t DVBGetDVBTime()
{
	int ret = 0;
	dvb_time_t stTime;
	
	mwDebug( "DVBGetDVBTime() - entry\r\n");
	stTime = DVBGetSystemTime();
	
	mwDebug( "DVBGetDVBTime() - return\r\n");
	
	return stTime;	
}

int DVBGetAllServices(dvb_service_info_t* pstServices, unsigned int* pu32Cnt)
{
	int ret = 0;
	dvb_group_t* pstCurrentGroup;
	unsigned int i;
	dvb_tuner_t stTunerInfo;
	
	mwDebug( "DVBGetAllServices() - entry\r\n");
	pstCurrentGroup = DVBGetCurGroup();
	if(pstCurrentGroup)
	{
		if(pstServices && pu32Cnt && *pu32Cnt>=pstCurrentGroup->serviceCount)
		{
			for(i=0; i<pstCurrentGroup->serviceCount; i++)
			{
				ret = DVBGetServiceName(&pstCurrentGroup->Services[i], NULL, pstServices[i].m_as8ServiceName);
				if(ret != 0)
				{
					mwError("DVBGetAllServices() - DVBGetServiceName error\r\n");
				}
				DVBGetServiceTunerInfo(&pstCurrentGroup->Services[i], &stTunerInfo);
				pstServices[i].m_u16NetID = pstCurrentGroup->Services[i].netId;
				pstServices[i].m_u16ServiceID = pstCurrentGroup->Services[i].serviceId;
				pstServices[i].m_u16TsID = pstCurrentGroup->Services[i].tsId;
				pstServices[i].m_u32Band = stTunerInfo.bandwidth;
				pstServices[i].m_u32Freq = pstCurrentGroup->Services[i].frequence;
				if(pstCurrentGroup->FavId == GROUP_VIDEO)
					pstServices[i].m_u32ServiceType = DVB_GROUP_TV;
				else if(pstCurrentGroup->FavId == GROUP_AUDIO)
					pstServices[i].m_u32ServiceType = DVB_GROUP_RADIO;
				else
					pstServices[i].m_u32ServiceType = DVB_GROUP_USER_DEFINE;
				
				pstServices[i].m_u32IsDescramble = DVBIsServiceEncrypt(&pstCurrentGroup->Services[i]);
				pstServices[i].m_u32IsLocked = DVBServicesDBGetLock(&pstCurrentGroup->Services[i]);
				pstServices[i].m_u32IsUsed = DVBServicesDBGetUsed(&pstCurrentGroup->Services[i]);
				pstServices[i].m_u32Mod = stTunerInfo.modulation;
				DVBServicesDBGetType(&pstCurrentGroup->Services[i], &pstServices[i].m_u32ServiceType);
				pstServices[i].m_u32StereoMode = DVBServicesDBGetStereoMode(&pstCurrentGroup->Services[i]);
				pstServices[i].m_u32Sym = stTunerInfo.symbol_rate;
				pstServices[i].m_u32TunerType = stTunerInfo.tunertype;
				pstServices[i].m_u32Volume = DVBServicesDBGetVolume(&pstCurrentGroup->Services[i]);
				pstServices[i].m_u32ChannelNumber = DvbServicesDBGetLcn(&pstCurrentGroup->Services[i]);
			}
		}
		else if(pu32Cnt)
		{
			*pu32Cnt = pstCurrentGroup->serviceCount;
		}
	}
	else if(pu32Cnt)
	{
		*pu32Cnt = 0;
	}
	mwDebug( "DVBGetAllServices() - return\r\n");
	return ret;
}

int DVBManualTune(dvb_tuner_t* pstTunerInfo)
{
	int ret = 0;
	
	mwDebug( "DVBManualTune() - entry\r\n");
	if(pstTunerInfo)
	{
		ret = DVBTunerForceLock(pstTunerInfo);
	}
	mwDebug( "DVBManualTune() - return, ret = %d\r\n", ret);
	return ret;	
}

void DVBStartImportServices()
{
	int ret = 0;
	
	mwDebug( "DVBStartImportServices() - entry\r\n");
	ret = DVBNetWorkUpdateProgramStart();
	mwDebug( "DVBStartImportServices() - return\r\n");
	return;	
}

int DVBImportServices(dvb_networt_service_t* pstProgramList, unsigned int u32Num, unsigned int u32GroupIndex, const char* ps8GroupName)
{
	int ret = 0;
	
	mwDebug("DVBImportServices() - entry\r\n");
	
	ret = DvbNetWorkUpdateProgram(pstProgramList, u32Num, u32GroupIndex, ps8GroupName);
	
	mwDebug( "DVBImportServices() - return\r\n");
	return ret;
}

void DVBFinishImportServices()
{
	int ret = 0;
	
	mwDebug( "DVBFinishImportServices() - entry\r\n");
	ret = DVBNetWorkUpdateProgramStop();
	mwDebug( "DVBFinishImportServices() - return\r\n");
	return;
}

int DVBManualScan(dvb_tuner_t* stTunerInfo)
{
	int ret = 0;
	
	mwDebug( "DVBManualScan() - entry\r\n");
	ret = DvbBuilderManualSearch(stTunerInfo, DVBSearchCallback);
	eCurrentScan = DVB_SCAN_TYPE_MANUAL;
	mwDebug( "DVBManualScan() - return\r\n");
	return ret;
}

int DVBAutoScan( int startFreq, int endFreq)
{
	int ret = 0;
	
	mwDebug( "DVBAutoScan() - entry\r\n");
	eCurrentScan = DVB_SCAN_TYPE_AUTO;
	ret = DvbBuilderAcquaintance(DVBSearchCallback);
	//ret = DvbBuilderAutoSearch(DVBSearchCallback);
	mwDebug( "DVBAutoScan() - return\r\n");
	return ret;	
}

int DVBFullScan( int startFreq, int endFreq)
{
	int ret = 0;
	//dvb_tuner_t stStartFreq;
	//dvb_tuner_t stEndFreq;
	
	mwDebug( "DVBFullScan() - entry\r\n");
	u32StartFreq = startFreq;
	u32EndFreq = endFreq;
	eCurrentScan = DVB_SCAN_TYPE_FULL;
	ret = DvbBuilderAcquaintance(DVBSearchCallback);
#if 0
	stStartFreq.bandwidth = 8;
	stStartFreq.frequency = startFreq;
	stStartFreq.modulation = 64;
	stStartFreq.symbol_rate = 6875;
	stStartFreq.tunertype = TUNER_C;

	stEndFreq.bandwidth = 8;
	stEndFreq.frequency = endFreq;
	stEndFreq.modulation = 64;
	stEndFreq.symbol_rate = 6875;
	stEndFreq.tunertype = TUNER_C;
	ret = DvbBuilderFullSearch(&stStartFreq, &stEndFreq, DVBSearchCallback);
#endif
	mwDebug( "DVBFullScan() - return\r\n");
	return ret;	
}

int DVBAbortScan()
{
	int ret = 0;
	
	mwDebug( "DVBAbortScan() - entry\r\n");
	ret = DvbBuilderStopSearch();
	eCurrentScan = DVB_SCAN_TYPE_IDLE;
	mwDebug( "DVBAbortScan() - return\r\n");
	return ret;		
}

int DVBPlayServiceByIndex( int index)
{
	int ret = 0;
	
	mwDebug( "DVBPlayServiceByIndex() - entry, index = %d\r\n", index);
	ret = DVBServicePlayByIndex(0, index, NULL);
	mwDebug( "DVBPlayServiceByIndex() - return\r\n");
	return ret;
}

int DVBGetEitInfo(dvb_service_t* pstService, int type, dvb_event_t* pstEvent)
{
	int ret = -1;
	
	mwDebug( "DVBGetEitInfo() - entry\r\n");
	if(pstService)
	{
		ret = DVBEPGGetEitInfo(pstService, type, pstEvent);
	}
	mwDebug( "DVBGetEitInfo() - return, ret = %d\r\n", ret);
	return ret;
}

int DVBGetScheduleInfo(dvb_service_t* pstService, dvb_event_t* pstEventList, unsigned int* pu32Cnt)
{
	int ret = -1;
	unsigned int u32ScheduleCnt;
	unsigned int i;
	
	mwDebug( "DVBGetScheduleInfo() - entry\r\n");
	if(pstService && pu32Cnt)
	{
		u32ScheduleCnt = DVBEPGGetScheEventCount(pstService);
		if(pstEventList && *pu32Cnt>u32ScheduleCnt)
		{
			for(i=0; i<u32ScheduleCnt; i++)
			{
				DVBEPGGetScheInfo(pstService, i, &pstEventList[i]);
			}
		}
		*pu32Cnt = u32ScheduleCnt;
		ret = 0;
	}
	mwDebug( "DVBGetScheduleInfo() - return, ret = %d\r\n", ret);
	return ret;
}

int DVBSetFrequencyTable(dvb_frequency_t* pstFreqTable, unsigned int u32Num)
{
	int ret = 0;
	
	mwDebug( "DVBSetFrequencyTable() - entry\r\n");
	DvbBuilderSetFrequencyTable(pstFreqTable, u32Num);
	mwDebug( "DVBSetFrequencyTable() - return\r\n");
	return ret;	
}

static int DVBEnterFullOrAutoScan()
{
	int s32Ret = -1;
	switch(eCurrentScan)
	{
		case DVB_SCAN_TYPE_AUTO:
		{
			s32Ret = DvbBuilderAutoSearch(DVBSearchCallback);
			break;
		}
		case DVB_SCAN_TYPE_FULL:
		{
			dvb_tuner_t stStartFreq;
			dvb_tuner_t stEndFreq;
			
			stStartFreq.bandwidth = 8;
			stStartFreq.frequency = u32StartFreq;
			stStartFreq.modulation = 64;
			stStartFreq.symbol_rate = 6875;
			stStartFreq.tunertype = TUNER_C;

			stEndFreq.bandwidth = 8;
			stEndFreq.frequency = u32EndFreq;
			stEndFreq.modulation = 64;
			stEndFreq.symbol_rate = 6875;
			stEndFreq.tunertype = TUNER_C;
			s32Ret = DvbBuilderFullSearch(&stStartFreq, &stEndFreq, DVBSearchCallback);
			break;
		}
		default:
			mwError("DVBEnterFullOrAutoScan() - unknown search type\r\n");
			break;
	}

	return s32Ret;
}

int DVBSetDVBPluginPath(const char* ps8Path)
{
	int ret = 0;
	
	mwDebug( "DVBSetDVBPluginPath() - entry\r\n");
	ret = DvbBuilderLoadPlugin(ps8Path);
	if(ret == 0)
	{
		ret = DVBEnterFullOrAutoScan();
	}
	else
	{
		mwError("DVBSetDVBPluginPath() - load plugin msg failed\r\n");
	}
	mwDebug( "DVBSetDVBPluginPath() - return\r\n");
	return ret;		
}

void DVBStopDVBService()
{
	int ret = 0;
	
	mwDebug( "DVBStopDVBService() - entry\r\n");
	ret = DVBServicePlayStop(0);
	mwDebug( "DVBStopDVBService() - return\r\n");
	return;	
}

void DVBStandby()
{
	mwDebug( "DVBStandby() - entry\r\n");
	DVBTunerStandby();
	DVBDecoderDeinit();
	mwDebug( "DVBStandby() - return\r\n");
}

void DVBResume()
{
	mwDebug( "DVBResume() - entry\r\n");
	DVBTunerResume();
	mwDebug( "DVBResume() - return\r\n");
}


pfDvbDebug pfDebugOutputs = NULL;

static void DVBDebug(unsigned int u32Level, const char* ps8String)
{
	if(pfDebugOutputs)
	{
		if(u32Level == MW_DEBUG_COMMON)
			pfDebugOutputs(DVB_DEBUG_LEVEL_COMMON, ps8String);
		else if(u32Level == MW_DEBUG_ERROR)
			pfDebugOutputs(DVB_DEBUG_LEVEL_ERROR, ps8String);
	}
}

void DVBRegistorDebugFun(pfDvbDebug pfDvbDebugFun)
{
	pfDebugOutputs = pfDvbDebugFun;
	mwRegistorDebugFunction(DVBDebug);
	CI_RegistorDebugFun(DVBDebug);
}

static int SptsDataOutput(unsigned char* pu8Ts, unsigned int u32Len)
{
	int ret;
	//LOGE("--->%s, call DEC_SptsOut, u16Len = %d", __FUNCTION__, u16Len);
	ret = DEC_SptsOut(pu8Ts, u32Len);
	//LOGE("<---%s, DEC_SptsOut out, ret = %d", __FUNCTION__, ret);
	
	send_live_data(pu8Ts, u32Len);
}

static void StartPlayerNotifyToCall(spts_notify_status_t status)
{
	unsigned int param;
	void* pParam = NULL;

	mwDebug("StartPlayerNotifyToCall() - entry, status = %d\r\n", status);
	if(pfCallback)
	{
		if(status == SPTS_SI_OK)//MSG_SERVICE_HAS_TS
		{
			param = MSG_SERVICE_HAS_TS;
			pfCallback(DVB_CB_TYPE_SERVICE, param, pParam);
		}
		else if(status == SPTS_STREAM_FREE)//MSG_SERVICE_FREE_AND_RESET_PLAYER
		{
			param = MSG_SERVICE_FREE_AND_RESET_PLAYER;
			pfCallback(DVB_CB_TYPE_SERVICE, param, pParam);			
		}
		else if(status == SPTS_STREAM_ENCRY)//MSG_SERVICE_SCRAMBLED
		{
			param = MSG_SERVICE_SCRAMBLED;
			pfCallback(DVB_CB_TYPE_SERVICE, param, pParam);			
		}
	}
	mwDebug("StartPlayerNotifyToCall() - return\r\n");

	return;
}

static void DecStatusNotifyToCall(DEC_STATUS_T status)
{
	if(pfCallback)
	{
		
	}
	return;
}

static void SignalBadNotifyToCall(int signalStatus)//signalStatus, 0-signal good, 1-signal bad, 2-no ts out
{
	unsigned int param;
	void* pParam = NULL;
	
	if(pfCallback)
	{
		if(signalStatus == 0)//MSG_SERVICE_SIGNAL_GOOD
		{
			param = MSG_SERVICE_SIGNAL_GOOD;
			pfCallback(DVB_CB_TYPE_SERVICE, param, pParam);				
		}
		else if(signalStatus == 1 || signalStatus == 2)//MSG_SERVICE_SIGNAL_BAD
		{
			param = MSG_SERVICE_SIGNAL_BAD;
			pfCallback(DVB_CB_TYPE_SERVICE, param, pParam);				
		}
	}	
	return;
}

static int IsOnce=0;
int DVBInitialize(char *appFilesDir)
{
	int ret;
	if(IsOnce!=0)
		return ;
		
	mwDebug( "DVBInitialize() - entry, build time %s\r\n", __DATE__""__TIME__);
	ret = DVBSystemInitialize(appFilesDir);
	DVBRegisterDvbInitDoneNotify(DVBInitCallback);
	
	ret = ci_init();
	liveTsSendInit();

	if(-1 == DVBDecoderLoadSymbol())
	{
		SPTS_RegisterOutputFun((pfSPTSDataGot)send_live_data);
	}
	else
	{
		SPTS_RegisterOutputFun(SptsDataOutput);
	}
	
	SPTS_RegisterStartPlayerFun(StartPlayerNotifyToCall);
	DVBDecoderRegisterStartPlayerFun(DecStatusNotifyToCall);
	DvbRegisterSignalBadNotify((pSignalBadNotify)SignalBadNotifyToCall);
	IsOnce++;
	//set path
	DVBSetDVBPluginPath(DVBGetPluginPath());
	mwDebug( "DVBInitialize() - ret = %d", ret);
	return ret;
}

int DVBTerminate()
{
	int ret = 0;
	
	mwDebug( "DVBTerminate() - entry\r\n");
	ret = DVBSystemDeinitialize(DVBInitCallback);	
	mwDebug( "DVBTerminate() - return\r\n");
	return ret;
}

int DVBRegistorCallback(pfDVBCallback pfCb)
{
	pfCallback = pfCb;

	return 0;
}

int DVBDeviceStatusChanged(unsigned char status, int fd)
{
	int ret = 0;
	
	mwDebug( "DVBDeviceStatusChanged() - entry\r\n");
	ret = CamUsbStatusChangedNotify(status, fd);
	mwDebug( "DVBDeviceStatusChanged() - return\r\n");
	return ret;
}
